package org.dromara.netbar.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import org.dromara.common.core.constant.NetbarConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.enums.FormatsType;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.AssertUtils;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.netbar.domain.NetbarCouponMember;
import org.dromara.netbar.domain.bo.NetbarCouponMemberBo;
import org.dromara.netbar.domain.vo.NetbarCouponMemberVo;
import org.dromara.netbar.domain.vo.NetbarMemberLevelVo;
import org.dromara.netbar.domain.vo.NetbarSeatTypeVo;
import org.dromara.netbar.mapper.NetbarCouponMemberMapper;
import org.dromara.netbar.service.INetbarMemberLevelService;
import org.dromara.netbar.service.INetbarSeatTypeService;
import org.springframework.stereotype.Service;
import org.dromara.netbar.domain.bo.NetbarCouponBo;
import org.dromara.netbar.domain.vo.NetbarCouponVo;
import org.dromara.netbar.domain.NetbarCoupon;
import org.dromara.netbar.mapper.NetbarCouponMapper;
import org.dromara.netbar.service.INetbarCouponService;

import java.math.BigDecimal;
import java.util.*;

/**
 * 通用卡券Service业务层处理
 *
 * @author Lion Li
 * @date 2025-07-09
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class NetbarCouponServiceImpl implements INetbarCouponService {

    private final NetbarCouponMapper baseMapper;

    private final NetbarCouponMemberMapper netbarCouponMemberMapper;

    private final INetbarSeatTypeService netbarSeatTypeService;

    private final INetbarMemberLevelService memberLevelService;
    /**
     * 查询通用卡券
     *
     * @param couponId 主键
     * @return 通用卡券
     */
    @Override
    public NetbarCouponVo queryById(Long couponId){
        return baseMapper.selectVoById(couponId);
    }

    /**
     * 分页查询通用卡券列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 通用卡券分页列表
     */
    @Override
    public TableDataInfo<NetbarCouponVo> queryPageList(NetbarCouponBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<NetbarCoupon> lqw = buildQueryWrapper(bo);
        Page<NetbarCouponVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        if (CollectionUtil.isNotEmpty(result.getRecords())) {
            long currentTimeMillis = System.currentTimeMillis();
            result.getRecords().stream()
                .filter(record -> record.getValidTermType() == 2 && record.getValidDateEnd().getTime() < currentTimeMillis)
                .forEach(record -> record.setIsExpired(true));
        }

        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的通用卡券列表
     *
     * @param bo 查询条件
     * @return 通用卡券列表
     */
    @Override
    public List<NetbarCouponVo> queryList(NetbarCouponBo bo) {
        LambdaQueryWrapper<NetbarCoupon> lqw = buildQueryWrapper(bo);
        List<NetbarCouponVo> netbarCouponVos = baseMapper.selectVoList(lqw);
        long currentTimeMillis = System.currentTimeMillis();
        netbarCouponVos.stream()
            .filter(record -> record.getValidTermType() == 2 && record.getValidDateEnd().getTime() < currentTimeMillis)
            .forEach(record -> record.setIsExpired(true));
        return netbarCouponVos;
    }

    private LambdaQueryWrapper<NetbarCoupon> buildQueryWrapper(NetbarCouponBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<NetbarCoupon> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(NetbarCoupon::getCouponId);
        if (StringUtils.isNotBlank(bo.getCouponType())) {
            lqw.eq(NetbarCoupon::getCouponType, bo.getCouponType());
        }
        lqw.eq(bo.getCouponAmount() != null, NetbarCoupon::getCouponAmount, bo.getCouponAmount());
        lqw.eq(bo.getPurchaseAmount() != null, NetbarCoupon::getPurchaseAmount, bo.getPurchaseAmount());
        lqw.eq(bo.getValidTermType() != null, NetbarCoupon::getValidTermType, bo.getValidTermType());
        lqw.eq(bo.getValidDateStart() != null, NetbarCoupon::getValidDateStart, bo.getValidDateStart());
        lqw.eq(bo.getValidDateEnd() != null, NetbarCoupon::getValidDateEnd, bo.getValidDateEnd());
        lqw.eq(bo.getIsAutoUse() != null, NetbarCoupon::getIsAutoUse, bo.getIsAutoUse());
        lqw.like(StringUtils.isNotBlank(bo.getCouponName()), NetbarCoupon::getCouponName, bo.getCouponName());
        lqw.eq(bo.getValidArea() != null, NetbarCoupon::getValidArea, bo.getValidArea());
        lqw.eq(bo.getHourDuration() != null, NetbarCoupon::getHourDuration, bo.getHourDuration());
        lqw.eq(StringUtils.isNotBlank(bo.getUsableTimeStart()), NetbarCoupon::getUsableTimeStart, bo.getUsableTimeStart());
        lqw.eq(StringUtils.isNotBlank(bo.getUsableTimeEnd()), NetbarCoupon::getUsableTimeEnd, bo.getUsableTimeEnd());
        lqw.eq(bo.getDiscountRate() != null, NetbarCoupon::getDiscountRate, bo.getDiscountRate());
        return lqw;
    }

    /**
     * 新增通用卡券
     *
     * @param bo 通用卡券
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(NetbarCouponBo bo) {
        validEntityBeforeSave(bo);
        bo.setHourDuration(generateHourDuration(bo));
        NetbarCoupon add = MapstructUtils.convert(bo, NetbarCoupon.class);
        add.setCouponName(generateCouponName(bo));
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setCouponId(add.getCouponId());
        }
        return flag;
    }

    /**
     * 计算包时券可用时长
     * @param bo
     * @return
     */
    private Long generateHourDuration(NetbarCouponBo bo) {
        if (NetbarConstants.Coupon.TYPE_2.equals(bo.getCouponType())) {
            return bo.getHourDuration();
        }
        if(StringUtils.isEmpty(bo.getUsableTimeEnd()) || StringUtils.isEmpty(bo.getUsableTimeStart())) {
             return 0L;
        }
        if (Long.parseLong(bo.getUsableTimeEnd()) > Long.parseLong(bo.getUsableTimeStart())) {
            return Long.parseLong(bo.getUsableTimeEnd()) - Long.parseLong(bo.getUsableTimeStart());
        }
        return (24 - Long.parseLong(bo.getUsableTimeStart())) + Long.parseLong(bo.getUsableTimeEnd());
    }

    /**
     * 生成券名称
     */
    @Override
    public String generateCouponName(NetbarCouponBo bo){
        // 券类型
        String couponName = "【"+ bo.getCouponType() +"】";
        if (NetbarConstants.Coupon.TYPE_5.equals(bo.getCouponType())) {
            List<NetbarMemberLevelVo> netbarMemberLevelVos = memberLevelService.listMemberLevelByIds(Collections.singletonList(bo.getMemberLevelId()));
            couponName += netbarMemberLevelVos.get(0).getLevelName() + " ";
        }else if (NetbarConstants.Coupon.TYPE_1.equals(bo.getCouponType())) {
            // 网费券
            couponName += (bo.getCouponAmount() / 100) + "元" + NetbarConstants.Coupon.TYPE_1;
        }else if(NetbarConstants.Coupon.TYPE_6.equals(bo.getCouponType())){
            // 代金券
            couponName += (bo.getCouponAmount() / 100) + "元" + NetbarConstants.Coupon.TYPE_6;
            return couponName;
        }else{
            // 区域
            if (0 == bo.getValidArea()) {
                couponName += "全区域 ";
            }else{
                List<NetbarSeatTypeVo> netbarSeatTypeVoList = netbarSeatTypeService.getSeatTypeVos();
                Optional<NetbarSeatTypeVo> first = netbarSeatTypeVoList.stream().filter(n -> n.getSeatTypeId().equals(bo.getValidArea())).findFirst();
                AssertUtils.isTrue(first.isPresent(), "券区域不存在");
                couponName += first.get().getSeatTypeName() + " ";
            }

            if (NetbarConstants.Coupon.TYPE_4.equals(bo.getCouponType())) {
                couponName += (bo.getDiscountRate() % 10 == 0 ? bo.getDiscountRate() / 10 : bo.getDiscountRate()) + "折折扣券";
            }else if (NetbarConstants.Coupon.TYPE_2.equals(bo.getCouponType())) {
                couponName += bo.getHourDuration() + "小时" + bo.getCouponType();
            }else if(NetbarConstants.Coupon.TYPE_3.equals(bo.getCouponType())){
                couponName += bo.getUsableTimeStart() +"点-" + bo.getUsableTimeEnd() +"点"+ bo.getCouponType();
            }
        }
        // 有效期
        if(1 == bo.getValidTermType()){
            couponName += "（永久）";
        }else if(2 == bo.getValidTermType()){
            String validStartDate = DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_chs, bo.getValidDateStart());
            String validEndDate = DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_chs, bo.getValidDateEnd());
            couponName += "（"+ validStartDate +"-"+ validEndDate +"）";
        }
        couponName += (1 == bo.getIsAutoUse()) ? "（自动）" : "（手动）";
        return couponName;
    }

    @Override
    /**
     * 获取优惠券名称和ID列表，并标记过期状态
     * @return 优惠券VO列表
     */
    public List<NetbarCouponVo> listCouponNameAndId() {
        // 查询优惠券ID和名称
        List<NetbarCouponVo> netbarCouponVos = baseMapper.selectVoList(
            new LambdaQueryWrapper<NetbarCoupon>()
                .select(NetbarCoupon::getCouponId, NetbarCoupon::getCouponType,NetbarCoupon::getCouponName, NetbarCoupon::getValidTermType, NetbarCoupon::getValidDateEnd)
        );

        // 空列表直接返回
        if (CollectionUtil.isEmpty(netbarCouponVos)) {
            return netbarCouponVos;
        }

        // 获取当前时间戳
        long currentTimeMillis = System.currentTimeMillis();
        // 使用stream优化循环，标记过期优惠券
        netbarCouponVos.stream()
            .filter(record -> record.getValidTermType() == 2 && record.getValidDateEnd().getTime() < currentTimeMillis)
            .forEach(record -> record.setIsExpired(true));

        return netbarCouponVos;
    }

    @Override
    public Map<Long, Integer> countMapBySeatTypeIds(Long[] seatTypeIds) {
        if(null == seatTypeIds || 0 == seatTypeIds.length){
            return Collections.emptyMap();
        }
        return baseMapper.queryCountMapBySeatTypeIds(seatTypeIds);
    }

    @Override
    public List<NetbarCouponVo> queryByIds(List<Long> ids) {
        // TODO 加缓存
        return baseMapper.selectVoByIds(ids);
    }

    /**
     * 修改通用卡券
     *
     * @param bo 通用卡券
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(NetbarCouponBo bo) {
        validEntityBeforeSave(bo);
        bo.setHourDuration(generateHourDuration(bo));
        NetbarCoupon update = MapstructUtils.convert(bo, NetbarCoupon.class);
        update.setCouponName(generateCouponName(bo));
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(NetbarCouponBo entity){
        // 非 等于 代金券,包时券，代金券，折扣券 拦截
        AssertUtils.isTrue(NetbarConstants.Coupon.TYPE_1.equals(entity.getCouponType()) || NetbarConstants.Coupon.TYPE_2.equals(entity.getCouponType()) ||
            NetbarConstants.Coupon.TYPE_3.equals(entity.getCouponType()) || NetbarConstants.Coupon.TYPE_4.equals(entity.getCouponType()) || NetbarConstants.Coupon.TYPE_5.equals(entity.getCouponType()) || NetbarConstants.Coupon.TYPE_6.equals(entity.getCouponType()
        ), "请选择正确的券类型");
        //TODO 做一些数据校验,如唯一约束
        AssertUtils.notEmpty(entity.getCouponType(), "请选择卡券类型");
        AssertUtils.notNull(entity.getPurchaseAmount(), "请输入购买金额");

        if (NetbarConstants.Coupon.TYPE_1.equals(entity.getCouponType())) {
            AssertUtils.notNull(entity.getCouponAmount(), "请输入卡券金额");
        }
        AssertUtils.notNull(entity.getValidTermType(), "请选择有效期类型");
        if (2 == entity.getValidTermType()) {
            // 范围
            AssertUtils.notNull(entity.getValidDateStart(), "请选择有效期开始时间");
            AssertUtils.notNull(entity.getValidDateEnd(), "请选择有效期结束时间");
        }
        if(NetbarConstants.Coupon.TYPE_5.equals(entity.getCouponType())){
            // 升级券
            AssertUtils.notNull(entity.getCouponAmount(), "请输入卡券金额");
            AssertUtils.notNull(entity.getEffectiveAmount(), "请输入生效金额");
            AssertUtils.notNull(entity.getMemberLevelId(), "请选择会员等级");
        } else if(NetbarConstants.Coupon.TYPE_2.equals(entity.getCouponType()) ||
            NetbarConstants.Coupon.TYPE_3.equals(entity.getCouponType())){
            AssertUtils.notNull(entity.getValidArea(), "请选择有效区域");
            AssertUtils.notNull(entity.getUsableTimeStart(), "请选择可用开始时间");
            AssertUtils.notNull(entity.getUsableTimeEnd(), "请选择可用结束时间");
        }else if(NetbarConstants.Coupon.TYPE_4.equals(entity.getCouponType())){
            AssertUtils.notNull(entity.getValidArea(), "请选择有效区域");
            AssertUtils.notNull(entity.getDiscountRate(), "请输入折扣力度");
        }
        AssertUtils.notNull(entity.getIsAutoUse(), "请选择是否自动使用");
    }

    /**
     * 校验并批量删除通用卡券信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }
}
